<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1" import="java.util.*, javax.net.ssl.*, java.security.Security, java.net.*, java.io.*, javax.xml.parsers.*, org.apache.commons.lang.StringEscapeUtils, javax.xml.transform.*, javax.xml.transform.dom.*, javax.xml.transform.stream.* , org.xml.sax.*, org.json.simple.*, org.json.simple.parser.*, java.util.zip.*, org.w3c.dom.*, org.OpenGeoPortal.Download.* "%>
<%!    	 
	  /**
	 * This jsp should receive a POST request with an object containing 
	 * all the info needed for each layer to be downloaded.  The jsp calls a class 
	 * that will create a download directory if it doesn't exist. Then the jsp will iterate over each layer, 
	 * calling a class that will download each into the directory, using the 
	 * appropriate method.  Once this is complete the jsp will call another class to 
	 * zip the directory contents, delete the original files, and the jsp will return a link to the
	 * zip-file...this allows us to leverage AJAX methods.  There may also be 
	 * an option to email a link to the zip-file to the user.
	 * @author Chris Barnett
	 */
	 
	private void addFilesToZipArchive(File[] filesToZip, File zipFile)
	throws Exception
	{
		System.out.println("packaging files...");
		byte[] buffer = new byte[1024 * 1024];
		long startTime = System.currentTimeMillis();
	    ZipOutputStream newZipStream = new ZipOutputStream(new FileOutputStream (zipFile));
	    int zipFileCounter = 0;
	    for (int i = 0; i < filesToZip.length; i++) {
	    	if (filesToZip[i] == null){
	    		continue;
	    	}
			FileInputStream currentFileStream = new FileInputStream(filesToZip[i]);
	    	zipFileCounter++;

	    	if (!filesToZip[i].getName().contains(".zip")){
	    		//add this stand-alone file to the archive
	    		int bytesRead;
	            while ((bytesRead = currentFileStream.read(buffer))!= -1) {
		        	String entryName = filesToZip[i].getName();
		        	System.out.println(entryName);
		        	ZipEntry zipEntry = new ZipEntry(entryName);
			    	newZipStream.putNextEntry(zipEntry);
	                newZipStream.write(buffer, 0, bytesRead);
	            }
	    	} else {
	    		ZipInputStream currentZipStream = new ZipInputStream(currentFileStream);
	    		ZipEntry currentEntry;
	        	while ((currentEntry = currentZipStream.getNextEntry()) != null) {
	        		String entryName = currentEntry.getName();
	        		System.out.println(entryName);
	        		ZipEntry zipEntry = new ZipEntry(entryName);
		    		newZipStream.putNextEntry(zipEntry);
	            	int bytesRead;
	            	while ((bytesRead = currentZipStream.read(buffer))!= -1) {
	                	newZipStream.write(buffer, 0, bytesRead);
	           	 	}
	        	}
	        	currentZipStream.close();
	    	}
	        filesToZip[i].delete();
	     }

	    if (zipFileCounter > 0){
	     	newZipStream.close();
	    }

		long endTime = System.currentTimeMillis();
		System.out.println(zipFileCounter + " file(s) zipped in " + (endTime - startTime) + " milliseconds.");
	}

	/**
	 * send query to Solr and return results, based on Steve's code in Searcher.java
	 * @param layerIds
	 * @return layerInfoMap
	 */
	private static Map<String, Map<String, String>> getDownloadInfoFromSolr(String[] layerIds)
	throws Exception
	{
		//String serverName = "localhost";
		String serverName = "geoportal-demo.atech.tufts.edu";
	 	String port = "80";
	 	String layerIdsString = "";
	 	int j = layerIds.length;
		for(int i = 0; i < j - 1; i++){
			layerIdsString += "LayerId:" + layerIds[i] + "+OR+";
		}
		layerIdsString += "LayerId:" + layerIds[j - 1];
		String returnedColumns = "Name,Institution,Access,DataType,Availability,Location,FgdcText,LayerId,WorkspaceName,SrsProjectionCode";
		String solrQuery = "q=" + layerIdsString + "&fl=" + returnedColumns;
	 	String url$ = "http://" + serverName + ":" + port + "/solr/select/?" + solrQuery 
	 				  + "&debugQuery=off&version=2.2&indent=on&wt=json";
	 	
	 	//System.out.println(url$);
		try
		{
			URL url = new URL(url$);
			InputStream inputStream = url.openStream();
			//System.out.println("inputStream = " + inputStream);
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
			String currentLine = bufferedReader.readLine();
			String resultRow = "";
			while (currentLine != null)
			{
				currentLine = currentLine.replaceAll("\\n|\\r", " ");
				resultRow += currentLine;	
				currentLine = bufferedReader.readLine();
			}
			//use simple json to parse the results and place into a hashmap 
			JSONParser parser = new JSONParser();
  			JSONObject jsonObj = (JSONObject) parser.parse(resultRow);
			JSONObject response = (JSONObject) jsonObj.get("response");
			String numFoundString = response.get("numFound").toString();
			int numFound = Integer.parseInt(numFoundString);
			JSONArray docs = (JSONArray) response.get("docs");

			Map<String,Map<String,String>> layerInfoMap = new HashMap<String, Map<String, String>>();
			for(int i = 0; i < numFound; i++){
				JSONObject currentResult = (JSONObject) docs.get(i);
				JSONArray currentKeyArray = (JSONArray) currentResult.get("LayerId");
				String currentKey = currentKeyArray.get(0).toString();
				Map<String,String> innerLayerInfoMap = new HashMap<String,String>();
				//this works, despite warnings
				innerLayerInfoMap = (Map <String, String>) currentResult;
				//temporary...EPSG code handling should occur elsewhere
				innerLayerInfoMap.put("SRS", "4326");
				layerInfoMap.put(currentKey, innerLayerInfoMap);
			}
			//System.out.println(layerInfoMap.toString());
			return layerInfoMap;
			
		}
		catch (IOException e)
		{
			System.out.println("error in getDownloadInfoFromSolr with url = " + url$);
			return new HashMap<String, Map<String, String>>();
		}
		
		catch (ParseException e)
		{
			System.out.println("error parsing JSON object in getDownloadInfoFromSolr with url = " + url$);
			return new HashMap<String, Map<String, String>>();
		}
		
	}
	
	 private URLConnection sendWfsRequest(String wfsServerAddress, String postRequest)
	 throws IOException, MalformedURLException
	 {
			String url$ = "http://" + wfsServerAddress + "/wfs";
			URL url = new URL(url$);
	    	System.out.println("Sending POST request to " + url$ + ": " + postRequest);
			URLConnection urlConnection = url.openConnection();
			urlConnection.setDoOutput(true);
			urlConnection.setDoInput(true); 
			urlConnection.setRequestProperty("Content-Type", "application/xml"); 

			//--write POST message to the network stream
			DataOutputStream outputStream = new DataOutputStream(urlConnection.getOutputStream());
			outputStream.writeBytes(postRequest);
			outputStream.close();
			
			return urlConnection;
	 }
	 
	 private Map<String, String> getWfsDescribeLayerInfo(String layerName, String baseAddress)
	 	throws Exception
	 {
		//should be xml
		//do this later....
		/*DocumentFragment requestXML = createDocumentFragment();
		// Insert the root element node
		Element rootElement = requestXML.createElement("DescribeFeatureType");
		requestXML.appendChild(rootElement);*/

	 	String describeFeatureRequest = "<DescribeFeatureType"
	            + " version=\"1.0.0\""
	            + " service=\"WFS\""
	            + " xmlns=\"http://www.opengis.net/wfs\""
	            + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
	            + " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-basic.xsd\">"
	            + 	"<TypeName>" + layerName + "</TypeName>"
	            + "</DescribeFeatureType>";
	            
		URLConnection urlConnection = sendWfsRequest(baseAddress, describeFeatureRequest);

		InputStream inputStream = urlConnection.getInputStream();
		//write the contents of the InputStream to a character buffer?

		//parse the returned XML and return needed info as a map
		// Create a factory
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

		// Use document builder factory
		DocumentBuilder builder = factory.newDocumentBuilder();
		//Parse the document
		
		Document document = builder.parse(inputStream);
		//initialize return variable
		Map<String, String> describeLayerInfo = new HashMap<String, String>();

		//get the namespace info
		Node schemaNode = document.getFirstChild();
		NamedNodeMap schemaAttributes = schemaNode.getAttributes();
		for (int i = 0; i < schemaAttributes.getLength(); i++){
			Node currentNode = schemaAttributes.item(i);
			String targetNamespace = "targetNamespace";
			String currentName = currentNode.getNodeName();
			if (currentName.equals(targetNamespace)){
				describeLayerInfo.put("nameSpace", currentNode.getNodeValue());
			} else if ((currentName.equals("xmlns:xsd"))||(currentName.equals("xmlns:gml"))||
					(currentName.equals("elementFormDefault"))){

			} else {
				//doesn't seem to be a built in way to get this via the api
				int localNamePosition = currentNode.getNodeName().indexOf(":") + 1;
				String workSpace = currentNode.getNodeName().substring(localNamePosition);
				describeLayerInfo.put("workSpace", workSpace);
			}
		}
		
		//we can get the geometry column name from here
		NodeList elementNodes = document.getElementsByTagName("xsd:element");
		
		for (int i = 0; i < elementNodes.getLength(); i++){
			Node currentNode = elementNodes.item(i);
			NamedNodeMap currentAttributeMap = currentNode.getAttributes();
			String attributeValue = null;
			for (int j = 0; j < currentAttributeMap.getLength(); j++){
				Node currentAttribute = currentAttributeMap.item(j);
				String currentAttributeName = currentAttribute.getNodeName();
				if (currentAttributeName.equals("name")){
					attributeValue = currentAttribute.getNodeValue();
				} else if (currentAttributeName.equals("type")){
					if (currentAttribute.getNodeValue().startsWith("gml:")){
						describeLayerInfo.put("geometryColumn", attributeValue);
						break;
					}
				}
				//System.out.println(currentAttribute.getNodeName());
			}

		}
		
		
		return describeLayerInfo;
	 }
	 
	 private Map<String, String> getDescribeCoverage(String layerName, String baseAddress)
	 	throws Exception
	 {
		//should be xml
		//do this later....
		/*DocumentFragment requestXML = createDocumentFragment();
		// Insert the root element node
		Element rootElement = requestXML.createElement("DescribeFeatureType");
		requestXML.appendChild(rootElement);*/

	 	String describeFeatureRequest = "<DescribeFeatureType"
	            + " version=\"1.0.0\""
	            + " service=\"WFS\""
	            + " xmlns=\"http://www.opengis.net/wfs\""
	            + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
	            + " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-basic.xsd\">"
	            + 	"<TypeName>" + layerName + "</TypeName>"
	            + "</DescribeFeatureType>";
	            
		URLConnection urlConnection = sendWfsRequest(baseAddress, describeFeatureRequest);

		InputStream inputStream = urlConnection.getInputStream();
		//write the contents of the InputStream to a character buffer?

		//parse the returned XML and return needed info as a map
		// Create a factory
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

		// Use document builder factory
		DocumentBuilder builder = factory.newDocumentBuilder();
		//Parse the document
		
		Document document = builder.parse(inputStream);
		//initialize return variable
		Map<String, String> describeLayerInfo = new HashMap<String, String>();

		//get the namespace info
		Node schemaNode = document.getFirstChild();
		NamedNodeMap schemaAttributes = schemaNode.getAttributes();
		for (int i = 0; i < schemaAttributes.getLength(); i++){
			Node currentNode = schemaAttributes.item(i);
			String targetNamespace = "targetNamespace";
			String currentName = currentNode.getNodeName();
			if (currentName.equals(targetNamespace)){
				describeLayerInfo.put("nameSpace", currentNode.getNodeValue());
			} else if ((currentName.equals("xmlns:xsd"))||(currentName.equals("xmlns:gml"))||
					(currentName.equals("elementFormDefault"))){

			} else {
				//doesn't seem to be a built in way to get this via the api
				int localNamePosition = currentNode.getNodeName().indexOf(":") + 1;
				String workSpace = currentNode.getNodeName().substring(localNamePosition);
				describeLayerInfo.put("workSpace", workSpace);
			}
		}
		
		//we can get the geometry column name from here
		NodeList elementNodes = document.getElementsByTagName("xsd:element");
		
		for (int i = 0; i < elementNodes.getLength(); i++){
			Node currentNode = elementNodes.item(i);
			NamedNodeMap currentAttributeMap = currentNode.getAttributes();
			String attributeValue = null;
			for (int j = 0; j < currentAttributeMap.getLength(); j++){
				Node currentAttribute = currentAttributeMap.item(j);
				String currentAttributeName = currentAttribute.getNodeName();
				if (currentAttributeName.equals("name")){
					attributeValue = currentAttribute.getNodeValue();
				} else if (currentAttributeName.equals("type")){
					if (currentAttribute.getNodeValue().startsWith("gml:")){
						describeLayerInfo.put("geometryColumn", attributeValue);
						break;
					}
				}
				//System.out.println(currentAttribute.getNodeName());
			}

		}
		
		
		return describeLayerInfo;
	 }
	 
	 private File wfsDownload(Map<String, String> layerInfo, String[] bbox, File localDir, String baseAddress)
		throws Exception
	{
 	//all client bboxes should be passed as lat-lon coords.  we will need to get the appropriate epsg code for the layer
 	//in order to return the file in original projection to the user (will also need to transform the bbox)
 		System.out.println("Downloading Layer..." + layerInfo.get("Name"));
		//--generate POST message
		//info needed: geometry column, bbox coords, epsg code, workspace & layername
		String workSpace = layerInfo.get("WorkspaceName");
		Map<String, String> describeLayerInfo = getWfsDescribeLayerInfo(workSpace + ":" + layerInfo.get("Name"), baseAddress);
		String geometryColumn = describeLayerInfo.get("geometryColumn");
		String nameSpace = describeLayerInfo.get("nameSpace");
		//should be xml
		String getFeatureRequest = "<wfs:GetFeature service=\"WFS\" version=\"1.1.0\""
			+ " outputFormat=\"shape-zip\""
			+ " xmlns:" + workSpace + "=\"" + nameSpace + "\""
  			+ " xmlns:wfs=\"http://www.opengis.net/wfs\""
  			+ " xmlns:ogc=\"http://www.opengis.net/ogc\""
  			+ " xmlns:gml=\"http://www.opengis.net/gml\""
  			+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
  			+ " xsi:schemaLocation=\"http://www.opengis.net/wfs"
            + " http://schemas.opengis.net/wfs/1.1.0/wfs.xsd\">"
  			+ "<wfs:Query typeName=\"" + workSpace + ":" + layerInfo.get("Name") + "\">"
    		+	"<ogc:Filter>"
      		+		"<ogc:BBOX>"
        	+			"<ogc:PropertyName>" + geometryColumn + "</ogc:PropertyName>"
          	+			"<gml:Envelope srsName=\"http://www.opengis.net/gml/srs/epsg.xml#" + layerInfo.get("SRS") + "\">"
          	+				"<gml:lowerCorner>" + bbox[0] + " " + bbox[1] + "</gml:lowerCorner>"
          	+				"<gml:upperCorner>" + bbox[2] + " " + bbox[3] + "</gml:upperCorner>"
          	+			"</gml:Envelope>"
        	+		"</ogc:BBOX>"
      		+	"</ogc:Filter>"
  			+ "</wfs:Query>"
			+ "</wfs:GetFeature>";

		URLConnection urlConnection = sendWfsRequest(baseAddress, getFeatureRequest);

		InputStream inputStream = urlConnection.getInputStream();
		String responseContentType = urlConnection.getHeaderField("content-type");
		//System.out.println("Response Content-type is " + responseContentType);
		String fileExtension;
		if (responseContentType.equals("text/xml")){
			fileExtension = ".xml";
		} else if (responseContentType.equals("application/zip")){
			fileExtension = ".zip";
		} else {
			fileExtension = "";
		}
		File currentFile = new File(localDir, layerInfo.get("Name") + fileExtension);

		return writeToFile(inputStream, currentFile);
	}
	 
	 private File wcsDownload(Map<String, String> layerInfo, String[] bbox, File localDir, String baseAddress)
		throws Exception
	{
	//all client bboxes should be passed as lat-lon coords.  we will need to get the appropriate epsg code for the layer
	//in order to return the file in original projection to the user (will also need to transform the bbox)
		System.out.println("Downloading Layer..." + layerInfo.get("Name"));
		//--generate POST message
		//info needed: geometry column, bbox coords, epsg code, workspace & layername
		Map<String, String> describeLayerInfo = getDescribeCoverage(layerInfo.get("Name"), baseAddress);
		String geometryColumn = describeLayerInfo.get("geometryColumn");
		String workSpace = describeLayerInfo.get("workSpace");
		String nameSpace = describeLayerInfo.get("nameSpace");
		//should be xml
		String getFeatureRequest = "<wfs:GetFeature service=\"WFS\" version=\"1.1.0\""
			+ " outputFormat=\"shape-zip\""
			+ " xmlns:" + workSpace + "=\"" + nameSpace + "\""
			+ " xmlns:wfs=\"http://www.opengis.net/wfs\""
			+ " xmlns:ogc=\"http://www.opengis.net/ogc\""
			+ " xmlns:gml=\"http://www.opengis.net/gml\""
			+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
			+ " xsi:schemaLocation=\"http://www.opengis.net/wfs"
         	+ " http://schemas.opengis.net/wfs/1.1.0/wfs.xsd\">"
			+ "<wfs:Query typeName=\"" + workSpace + ":" + layerInfo.get("Name") + "\">"
 			+	"<ogc:Filter>"
   			+		"<ogc:BBOX>"
     		+			"<ogc:PropertyName>" + geometryColumn + "</ogc:PropertyName>"
       		+			"<gml:Envelope srsName=\"http://www.opengis.net/gml/srs/epsg.xml#" + layerInfo.get("SRS") + "\">"
       		+				"<gml:lowerCorner>" + bbox[0] + " " + bbox[1] + "</gml:lowerCorner>"
       		+				"<gml:upperCorner>" + bbox[2] + " " + bbox[3] + "</gml:upperCorner>"
       		+			"</gml:Envelope>"
     		+		"</ogc:BBOX>"
   			+	"</ogc:Filter>"
			+ "</wfs:Query>"
			+ "</wfs:GetFeature>";

		URLConnection urlConnection = sendWfsRequest(baseAddress, getFeatureRequest);

		InputStream inputStream = urlConnection.getInputStream();
		String responseContentType = urlConnection.getHeaderField("content-type");
		//System.out.println("Response Content-type is " + responseContentType);
		String fileExtension;
		if (responseContentType.equals("text/xml")){
			fileExtension = ".xml";
		} else if (responseContentType.equals("application/zip")){
			fileExtension = ".zip";
		} else {
			fileExtension = "";
		}
		File currentFile = new File(localDir, layerInfo.get("Name") + fileExtension);

		return writeToFile(inputStream, currentFile);
	}
	 
	 private File writeToFile(InputStream source, File sink)
	 throws IOException
	 {
		FileOutputStream fileOutputStream = new FileOutputStream(sink);
			//may need to tune this number for different systems
			byte[] buffer = new byte[128 * 1024];
			int currentBytes = source.read(buffer);
				while (currentBytes >= 0) {
				System.out.println("Receiving " + currentBytes + " bytes");
				//should store more bytes in buffer before writing to file
				fileOutputStream.write(buffer, 0, currentBytes);
				currentBytes = source.read(buffer);
			} 
			source.close();
			fileOutputStream.close();
			
			return sink;
	 }
	 
	 private File getXmlFileFromString(File downloadDirectory, String fileName, String xmlString)
	 throws Exception
	 {
			File xmlFile = new File(downloadDirectory, fileName);
			//parse the returned XML..do I really need to do this? why?
			// Create a factory
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			// Use document builder factory
			DocumentBuilder builder = factory.newDocumentBuilder();
			//Parse the document
			//for some reason, this is not being parsed
			InputStream xmlInputStream = new ByteArrayInputStream(xmlString.getBytes());
			Document document = builder.parse(xmlInputStream);
			document.setXmlStandalone(true);
			//debugging
			/*Node test1 = document.getFirstChild();
			System.out.println(test1.getNodeName());

			NodeList test2 = test1.getChildNodes();
			System.out.println(test1.hasChildNodes());
			System.out.println(test1.hasAttributes());
			Node test3 = test1.getFirstChild();
			System.out.println(test3.getNodeName());
			System.out.println(test3.hasChildNodes());
			System.out.println(test3.hasAttributes());
			for (int j = 0; j < test2.getLength(); j++){
				System.out.println(test2.item(j).getNodeName());
			}*/

		    try {
		        // Prepare the DOM document for writing
		        Source source = new DOMSource(document);

		        // Prepare the output file
		        Result result = new StreamResult(xmlFile);

		        // Write the DOM document to the file
		        Transformer xformer = TransformerFactory.newInstance().newTransformer();
		        xformer.transform(source, result);
		    } catch (TransformerConfigurationException e) {
		    } catch (TransformerException e) {}

		    return xmlFile;
	 }
	 
	 private File mitDownload(Map<String, String> layerInfo, String[] bbox, File localDir)
	 throws Exception
	 {
			System.out.println("Downloading Layer..." + layerInfo.get("Name"));
			//https://arrowsmith.mit.edu/php_scripts/geoweb/shpDownloadDirect.php?layer=bbox=geom=(point/arc/polygon)
			String layerName = layerInfo.get("Name");
			String geom = layerInfo.get("DataType").toLowerCase();
			if (geom.equals("line")){
				geom = "arc";
			}
			
			System.out.println(geom);
			//System.out.println(bbox.toString());
			String url$ = "https://arrowsmith.mit.edu/geoweb/php_scripts/shpDownloadDirectPublic.php?layer=" + layerName + "&bbox=" + bbox[0] + "," + bbox[1] + "," + bbox[2] + "," + bbox[3] + "&geom=" + geom;
			System.out.println(url$);
			URL url = null;
			// Create a trust manager that does not validate certificate chains
			TrustManager[] trustAllCerts = new TrustManager[]{
			    new X509TrustManager() {
			        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
			            return null;
			        }
			        public void checkClientTrusted(
			            java.security.cert.X509Certificate[] certs, String authType) {
			        }
			        public void checkServerTrusted(
			            java.security.cert.X509Certificate[] certs, String authType) {
			        }
			    }
			};

			// Install the all-trusting trust manager
			try {
			    SSLContext sc = SSLContext.getInstance("SSL");
			    sc.init(null, trustAllCerts, new java.security.SecureRandom());
			    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
			} catch (Exception e) {
			}

			// Now you can access an https URL without having the certificate in the truststore
			try {
			    url = new URL(url$);
			} catch (MalformedURLException e) {
			}

			URLConnection urlConnection = url.openConnection();
			urlConnection.setDoInput(true); 

			InputStream inputStream = urlConnection.getInputStream();
			String responseContentType = urlConnection.getHeaderField("content-type");
			String fileExtension;
			if (responseContentType.equals("text/xml")){
				fileExtension = ".xml";
			} else if (responseContentType.equals("application/zip")){
				fileExtension = ".zip";
			} else {
				fileExtension = "";
			}
			File currentFile = new File(localDir, layerInfo.get("Name") + ".zip");

			return writeToFile(inputStream, currentFile);
	 }
%>

<%
	String[] layerIds = request.getParameterValues("layers");
	String[] bbox = request.getParameterValues("bbox");
	//String clip = request.getParameter("clip");
	String height = request.getParameter("height");
	String width = request.getParameter("width");
	String format = request.getParameter("format");
	//System.out.println(System.getProperty("catalina.home"));
	try {
		//should use a web-accessible directory here
		String server = request.getServerName();
		//System.out.println(server);
		File tmpDir;
		if (server.equals("localhost")){
			tmpDir = new File(System.getProperty("catalina.home") + "/webapps/opengeoportal");
		} else {
			tmpDir = new File(System.getProperty("catalina.home") + "/sites/geoportal/webapps/ROOT");
		}
		//System.out.println(tmpDir.getAbsolutePath());
		if (!tmpDir.exists()){
			throw new IOException("The specified directory doesn't exist.");
		}
		String downloadDirString = "download";
		File downloadDir = new File(tmpDir, downloadDirString);
		if (!downloadDir.exists()){
			downloadDir.mkdir();
		}

		//loop over layers, determine appropriate method for download			
		//make a call to getLayerInfoFromSolr before loop, so we only
		//have to make one network connection to Solr server
		//return a hashmap of hashmaps
		Map <String, Map <String, String>> layerInfo = getDownloadInfoFromSolr(layerIds);
		int numLayers = layerIds.length;
		File[] allDownloads = new File[2 * numLayers];
		int fileCount = 0;
		for(int i = 0; i < numLayers; i++){
			//write code to make a determination about download method
			String institutionName = layerInfo.get(layerIds[i]).get("Institution");
			String dataType = layerInfo.get(layerIds[i]).get("DataType");

			if (institutionName.equals("Tufts")){
				File currentFile = null;
				if (dataType.equals("Raster") || dataType.equals("Paper Map")){
					currentFile = wcsDownload(layerInfo.get(layerIds[i]), bbox, downloadDir, "geoserver-dev.atech.tufts.edu");
				} else {
					currentFile = wfsDownload(layerInfo.get(layerIds[i]), bbox, downloadDir, "geoserver-dev.atech.tufts.edu");
				}
				allDownloads[i] = currentFile;
				String fileName = layerInfo.get(layerIds[i]).get("Name");
				//layernames contain periods
				fileName = fileName.replace(".", "_");
				fileName += ".shp.xml";
				String fgdcText = layerInfo.get(layerIds[i]).get("FgdcText").trim();
			
				File xmlMetadataFile = getXmlFileFromString(downloadDir, fileName, fgdcText);
		    	allDownloads[i + numLayers] = xmlMetadataFile;
		    	fileCount += 2;
			} else if (institutionName.equals("Harvard")){
				File currentFile = null;
				if (dataType.equals("Raster") || dataType.equals("Paper Map")){
					currentFile = wcsDownload(layerInfo.get(layerIds[i]), bbox, downloadDir, "dixon.hul.harvard.edu:8080/geoserver");
				} else {
					currentFile = wfsDownload(layerInfo.get(layerIds[i]), bbox, downloadDir, "dixon.hul.harvard.edu:8080/geoserver");
				}
				allDownloads[i] = currentFile;
				String fileName = layerInfo.get(layerIds[i]).get("Name");
				//layernames contain periods
				fileName = fileName.replace(".", "_");
				fileName += ".shp.xml";
				String fgdcText = layerInfo.get(layerIds[i]).get("FgdcText").trim();
			
				File xmlMetadataFile = getXmlFileFromString(downloadDir, fileName, fgdcText);
		    	allDownloads[i + numLayers] = xmlMetadataFile;
		    	fileCount += 2;
			} else if (institutionName.equals("MIT")){
				File currentFile = mitDownload(layerInfo.get(layerIds[i]), bbox, downloadDir);
				allDownloads[i] = currentFile;
				fileCount +=1;
			} else if (institutionName.equals("MassGIS")){
				File currentFile = wfsDownload(layerInfo.get(layerIds[i]), bbox, downloadDir, "giswebservices.massgis.state.ma.us/geoserver");
				allDownloads[i] = currentFile;
				String fileName = layerInfo.get(layerIds[i]).get("Name");
				//layernames contain periods
				fileName = fileName.replace(".", "_");
				fileName += ".shp.xml";
				String fgdcText = layerInfo.get(layerIds[i]).get("FgdcText").trim();
			
				File xmlMetadataFile = getXmlFileFromString(downloadDir, fileName, fgdcText);
		    	allDownloads[i + numLayers] = xmlMetadataFile;
		    	fileCount += 2;
			}
		}

		//create zip file; should generate a unique name
		String zipFileName = "openGeoportal" + System.currentTimeMillis() + ".zip";
		File zipFile = new File(downloadDir, zipFileName);
		File [] allDownloadsCompressed = new File[fileCount];
		System.arraycopy (allDownloads, 0, allDownloadsCompressed, 0, fileCount);

		addFilesToZipArchive(allDownloadsCompressed, zipFile);
		//return a status code...
		
		//return a link to the zip file, or info to create link  
		String returnLink = downloadDirString + "/" + zipFileName;
		PrintWriter writeToClient = response.getWriter();
		writeToClient.write(returnLink);
		    
	} catch(Exception e) {
		response.setStatus(500);
		e.printStackTrace();
	}	 
	 
%>
